package generator.workflow;

import generator.datastructure.MethodDeclaration;
import generator.datastructure.WritebleClass;
import generator.util.input_interpreter.ParallelizerInterpreter;

import java.util.List;

/** 
 * Esta clase es la encargada de realizar la adaptación de la clase original a gridificar para que 
 * esta utilice la clase Peer que contiene el/los métodos gridificados. Dicha adaptación consta de la 
 * creación y configuración de una instancia de la clase Peer asociada a la clase original y el
 * posterior reemplazo de la lógica contenida en el método a gridificar por un llamado al método
 * gridificado de la clase Peer.
 * @author Hirsch-Fernández
 */
public abstract class BindingManager {

	protected ParallelizerInterpreter pi;
	
	/**@return la clase original con las modificaciones necesarias que hacen que al invocar desde 
	 * otra clase el método a gridificar, se efectue dicho llamado sobre la clase Peer asociada, que
	 * contiene el/los métodos gridificados */
	protected abstract WritebleClass getStubClass();

	/**A través de este método se inserta, en el cuerpo del método a gridificar de la clase original, la
	 * sentencia de llamado al método gridificado perteneciente a la instancia de la clase peer creada
	 * previamente con el método {@link createPeerClassInstance(md)}  
	 * @param md
	 * 			representa la declaración del método que se pretende gridificar. De allí pueden extraerse
	 * 			datos tales como su nombre, parámetros de entrada y tipo de resultado devuelto, nombre y
	 * 			ubicación de la clase a	la que pertenece*/
	protected abstract void bindMethodCall(MethodDeclaration md);	
	
	/**A través de este método se inserta, en el cuerpo del método a gridificar de la clase original, las
	 * sentencias que permiten configurar la clase Peer, es decir, se copian todos los
	 * atributos de la clase original en la clase Peer asociada empleando los getters y setters  
	 * correspondientes de las clases involucradas (Peer y original).
	 * @param md
	 * 			representa la declaración del método que se pretende gridificar. De allí pueden extraerse
	 * 			datos tales como su nombre, parámetros de entrada y tipo de resultado devuelto, nombre y
	 * 			ubicación de la clase a	la que pertenece*/
	protected abstract void copyProperties(MethodDeclaration md);

	/**A través de este método se inserta, en el cuerpo del método a gridificar de la clase original, la
	 * sentencia de creación de la instancia de la clase Peer asociada, la cual contiene el/los métodos
	 * gridificados y a la cual se redirigirán los llamados al/los método/s que el ususario pretende
	 * gridificar.
	 * @param md
	 * 			representa la declaración del método que se pretende gridificar. De allí pueden extraerse
	 * 			datos tales como su nombre, parámetros de entrada y tipo de resultado devuelto, nombre y
	 * 			ubicación de la clase a	la que pertenece*/
	protected abstract void createPeerClassInstance(MethodDeclaration md);
	
	/**Este template method define el orden en el que deben aplicarse las diferentes adaptaciones que  
	 * sufrirá el/los método/s a paralelizar de la clase original.
	 * Cada cuerpo de un método a paralelizar será reemplazado por las siguientes sentencias:<BR>
	 * 1- creación de la instancia de la clase Peer<BR>
	 * 2- seteo de atributos de la clase original en la instancia creada de la clase Peer<BR>
	 * 3- retorno de resultado efectuando la invocación del método paralelizado residente en la clase Peer
	*/
	public WritebleClass bindPeerClass() {
		
		List<MethodDeclaration> methodsToGridify = pi.getMethodsToParallelize();
		
		for (MethodDeclaration md : methodsToGridify) {
			this.createPeerClassInstance(md);
			this.copyProperties(md);
			this.bindMethodCall(md);		
		}
		return getStubClass();		
	}
	
}
